﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace PPC_emulator
{
    public partial class MainForm : Form
    {
        Processor p;
        MemoryViewer memViewer;
        RegisterDialog regDialog;
        public MainForm()
        {
            InitializeComponent();
            p = new Processor(bpList);
            memViewer = new MemoryViewer(0x80000000, memViewGrid, memViewPAddress, memViewPValue, MemViewFPValue, p.ram);
            for (int i = 0; i < 40; i++)
            {
                bpList.shortRegTextBox[i].Click += clickReg;
            }
            regDialog = new RegisterDialog();
            MemViewShowMode.SelectedIndex = 0;
            memViewer.Update();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            Run();
        }

        public void Run()
        {
            string[] splitter = { "\r\n" };
            string[] ASMText = ASMInput.Text.Split(splitter, StringSplitOptions.RemoveEmptyEntries);
            foreach (string opc in ASMText)
            {
                ErrorCode error = p.process(opc);
                if (error != ErrorCode.Succes)
                {
                    ASMInput.Select(ASMInput.Text.IndexOf(opc), opc.Length);
                    System.Windows.Forms.ToolTip ErrorPopup = new System.Windows.Forms.ToolTip();
                    switch (error)
                    {
                        case ErrorCode.Unknown:
                            {
                                ErrorPopup.Show("The OP : " + opc + " is not valid.", this, ASMInput.Location, 5000);
                                break;
                            }
                        case ErrorCode.NoSpace:
                            {
                                ErrorPopup.Show("The OP : " + opc + " is not valid.\nA space is needed after the OP Code!", this, ASMInput.Location, 5000);
                                break;
                            }
                        case ErrorCode.InvalidRegister:
                            {
                                ErrorPopup.Show("The OP : " + opc + " is not valid.\nA register seems to be invalid, make sure it is between 0 and 31!", this, ASMInput.Location, 5000);
                                break;
                            }
                        case ErrorCode.OPCNotFound:
                            {
                                ErrorPopup.Show("The OP : " + opc + " is not valid.\nThe OP Code was not recognised. (Or not yet implemented)", this, ASMInput.Location, 5000);
                                break;
                            }
                        case ErrorCode.InvalidAddress:
                            {
                                ErrorPopup.Show("The OP : " + opc + " is not valid.\nThe address seems to be invalid.", this, ASMInput.Location, 5000);
                                break;
                            }
                    }

                }
                memViewer.Update();
            }
        }

        private void ASMInput_KeyDown(object sender, KeyEventArgs e)
        {
            if ((e.KeyData == Keys.F5))
                Run();
        }

        private void MemViewUpdate_Click(object sender, EventArgs e)
        {
            UInt32 vAddress = uint.Parse(memViewAValue.Text, System.Globalization.NumberStyles.HexNumber);
            vAddress &= 0xFFFFFFFC;
            if (vAddress < 0x80000000)
                vAddress = 0x80000000;
            if (vAddress > 0x81800000 - 0x100)
                vAddress = 0x81800000 - 0x100;
            memViewer.address = vAddress;
            memViewer.Update();
        }

        private void memViewPButton_Click(object sender, EventArgs e)
        {
            memViewer.poke();
            memViewer.Update();
        }

        private void clickReg(object sender, EventArgs e)
        {
            int register = int.Parse(((Control)sender).Tag.ToString());

            UInt32 value = p.registers.getRegister(register);

            if (regDialog.SetRegister(bpList.shortRegNames[register], ref value))
            {
                p.registers.setRegister(register-7, value);
                bpList.setRegister(register-7, value);
            }
        }

        private void MemViewScrollbar_ValueChanged(object sender, EventArgs e)
        {
            UInt32 vAddress;
            if (!GlobalFunctions.tryToHex(memViewAValue.Text, out vAddress))
            {
                MessageBox.Show("Invalid input");
                return;
            }
            if (!ValidMemory.validAddress(vAddress))
            {
                MessageBox.Show("Invalid address");
                return;
            }
            vAddress &= 0xFFFFFFFC;
            if (MemViewScrollbar.Value == 0)
                vAddress += 0x100;
            else if (MemViewScrollbar.Value == 2)
                vAddress -= 0x100;
            else
                return;
            if (vAddress < 0x80000000)
                vAddress = 0x80000000;
            if (vAddress > 0x81800000 - 0x100)
                vAddress = 0x81800000 - 0x100;

            //MemViewARange.SelectedIndexChanged -= MemViewARange_SelectedIndexChanged;
            //MemViewARange.SelectedIndex = ValidMemory.rangeCheckId(vAddress);
            //MemViewARange.SelectedIndexChanged += MemViewARange_SelectedIndexChanged;

            memViewer.address = vAddress;
            memViewAValue.Text = GlobalFunctions.toHex(vAddress);
            memViewer.Update();

            MemViewScrollbar.ValueChanged -= MemViewScrollbar_ValueChanged;
            MemViewScrollbar.Value = 1;
            MemViewScrollbar.ValueChanged += MemViewScrollbar_ValueChanged;

        }

        private void MemViewARange_SelectedIndexChanged(object sender, EventArgs e)
        {
            UInt32 sAddress = ValidMemory.ValidAreas[MemViewARange.SelectedIndex].low;
            memViewAValue.Text = GlobalFunctions.toHex(sAddress);
            memViewer.address = sAddress;
            memViewer.Update();
        }

        private void MemViewShowMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            MemoryViewMode vMode;
            switch (MemViewShowMode.SelectedIndex)
            {
                case 0:
                    vMode = MemoryViewMode.Hex;
                    break;
                case 1:
                    vMode = MemoryViewMode.ASCII;
                    break;
                case 2:
                    vMode = MemoryViewMode.ANSI;
                    break;
                default:
                    vMode = MemoryViewMode.Unicode;
                    break;
            }
            memViewer.viewMode = vMode;
            memViewer.Update();
        }
    }
}
